package com.yungee.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * HTTP请求
 */
public class HttpClientUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class);

    private static PoolingHttpClientConnectionManager cm = null;
    private static RequestConfig requestConfig = null;
    private static final int TIMEOUT = 3000;
    static {
        cm = new PoolingHttpClientConnectionManager();
        // 将最大连接数增加到200
        cm.setMaxTotal(200);
        // 将每个路由基础的连接增加到20
        cm.setDefaultMaxPerRoute(20);
        // Increase max total connection to 200
        cm.setMaxTotal(200);
        // Increase default max connection per route to 20
        cm.setDefaultMaxPerRoute(20);

        // HttpHost localhost = new HttpHost("www.yeetrack.com", 80);
        // cm.setMaxPerRoute(new HttpRoute(localhost), 50);

        requestConfig = RequestConfig.custom().setSocketTimeout(TIMEOUT).setConnectTimeout(TIMEOUT)
                .setConnectionRequestTimeout(TIMEOUT).build();
    }

    public static CloseableHttpClient getHttpClient() {
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
        return httpClient;
    }

    private static URI getUrl(String url) throws MalformedURLException, URISyntaxException {
        if (url != null && !url.startsWith("http")) {
            url = "http://" + url;
        }
        URL tmp = new URL(url);
        URI uri = new URI(tmp.getProtocol(), tmp.getUserInfo(), tmp.getHost(), tmp.getPort(), tmp.getPath(),
                tmp.getQuery(), null);
        return uri;
    }

    /**
     * 获取请求URL字符串
     */
    public static String getRealUrl(String url) {
        CloseableHttpClient httpClient = HttpClientUtil.getHttpClient();
        CloseableHttpResponse response = null;
        HttpContext httpContext = new BasicHttpContext();
        try {
            HttpGet httpGet = new HttpGet(getUrl(url));
            // 将HttpContext对象作为参数传给execute()方法,则HttpClient会把请求响应交互过程中的状态信息存储在HttpContext中
            response = httpClient.execute(httpGet, httpContext);
            // 获取重定向之后的主机地址信息,即"http://127.0.0.1:8088"
            HttpHost targetHost = (HttpHost) httpContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
            // 获取实际的请求对象的URI,即重定向之后的"/blog/admin/login.jsp"
            HttpUriRequest realRequest = (HttpUriRequest) httpContext.getAttribute(HttpCoreContext.HTTP_REQUEST);
            // System.out.println("主机地址:" + targetHost);
            // System.out.println("URI信息:" + realRequest.getURI());
            return targetHost.toString() + realRequest.getURI().toString();
            // HttpEntity entity = response.getEntity();
            // if(null != entity){
            // System.out.println("响应内容:" + EntityUtils.toString(entity,
            // ContentType.getOrDefault(entity).getCharset()));
            // EntityUtils.consume(entity);
            // }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
        return null;
    }

    private static Header[] assemblyHeader(Map<String, String> headers) {
        Header[] allHeader = new BasicHeader[headers.size()];
        int i = 0;
        for (String str : headers.keySet()) {
            allHeader[i] = new BasicHeader(str, headers.get(str));
            i++;
        }
        return allHeader;
    }

    /**
     * 发送Post请求
     */
    public static String executePost(String url, Map<String, String> params, Map<String, String> headers,
            String charSet) {
        CloseableHttpClient httpclient = getHttpClient();
        CloseableHttpResponse response = null;

        try {
            HttpPost post = new HttpPost(getUrl(url));

            if (headers != null) {
                post.setHeaders(assemblyHeader(headers));
            }

            // 设置HTTP POST请求参数必须用NameValuePair对象
            List<NameValuePair> lst = new ArrayList<NameValuePair>();
            for (Entry<String, String> entry : params.entrySet()) {
                lst.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            // 设置HTTP POST请求参数
            UrlEncodedFormEntity posEntity = new UrlEncodedFormEntity(lst, charSet);
            if (LOGGER.isDebugEnabled()) {
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                posEntity.writeTo(os);
                LOGGER.debug("url:{},content:{}", url, os.toString());
            }
            post.setEntity(posEntity);
            post.setConfig(requestConfig);

            response = httpclient.execute(post);
            HttpEntity entity = response.getEntity();
            String content = EntityUtils.toString(entity, charSet);
            return content;
        } catch (Exception e) {
            LOGGER.error(e.getMessage() + " when url is:" + url, e);
            return null;
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
    }

    public static String executePost(String url, Map<String, String> params, String charSet) {
        return executePost(url, params, null, charSet);
    }

    /**
     * 发送Get请求
     */
    public static String executeGet(String url, String charSet) {
        CloseableHttpClient httpclient = HttpClientUtil.getHttpClient();
        CloseableHttpResponse response = null;

        try {
            HttpGet getHtml = new HttpGet(getUrl(url));
            getHtml.setConfig(requestConfig);

            // String html = httpclient.execute(getHtml, responseHandler);
            response = httpclient.execute(getHtml);
            HttpEntity entity = response.getEntity();
            String html = EntityUtils.toString(entity, charSet);
            return html;
        } catch (Exception e) {
            LOGGER.error(e.getMessage() + " when url is:" + url);
            return null;
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 发送Get请求
     */
    public static String executeGet(String url, Map<String, String> header, String charSet) {
        CloseableHttpClient httpclient = HttpClientUtil.getHttpClient();
        CloseableHttpResponse response = null;

        try {
            HttpGet getHtml = new HttpGet(getUrl(url));

            if (header != null && !header.isEmpty()) {
                for (Entry<String, String> entry : header.entrySet()) {
                    getHtml.setHeader(entry.getKey(), entry.getValue());
                }
            }

            getHtml.setConfig(requestConfig);

            // String html = httpclient.execute(getHtml, responseHandler);
            response = httpclient.execute(getHtml);
            HttpEntity entity = response.getEntity();
            String html = EntityUtils.toString(entity, charSet);
            return html;
        } catch (Exception e) {
            LOGGER.error(e.getMessage() + " when url is:" + url);
            return null;
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 发送请求，去掉所有ssl验证
     */
    public static String postBody(String url, String postBody, Map<String, String> header, String charsetName) {
        CloseableHttpClient httpclient = HttpClientUtil.getHttpClient();
        CloseableHttpResponse response = null;
        String content = "";

        try {
            HttpPost httppost = new HttpPost(getUrl(url));
            if (header != null && !header.isEmpty()) {
                for (Entry<String, String> entry : header.entrySet()) {
                    httppost.setHeader(entry.getKey(), entry.getValue());
                }
            }

            if (postBody == null) {
                postBody = "";
            }
            HttpEntity postEntity = new StringEntity(postBody, charsetName);
            httppost.setEntity(postEntity);
            httppost.setConfig(requestConfig);

            response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();
            StringBuilder sb = new StringBuilder();
            BufferedReader red = new BufferedReader(new InputStreamReader(entity.getContent(), charsetName));
            String line;
            while ((line = red.readLine()) != null) {
                sb.append(line + "\n");
            }
            EntityUtils.consume(entity);
            content = sb.toString();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            // 释放连接
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }

        return content;
    }
}